package websocketUtils

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"sync"
)

type IWriter interface {
	ReadMessageHandle(conn *websocket.Conn, handles ...handle)
	WriterMessage(messageType int, data []byte, targetConns ...*websocket.Conn)
}

type WsMsg struct {
	inChan    chan []byte
	outChan   chan []byte
	closeChan chan byte
	mutex     sync.Mutex // 对closeChan关闭上锁
	isClosed  bool       // 防止closeChan被关闭多次
}

type handle = func(conn *websocket.Conn)

func (r *WsMsg) ReadMessageChan() (data []byte, err error) {

	select {
	case data = <-r.inChan:
	case <-r.closeChan:
		err = errors.New("connection is closeed")
	}
	return
}
func (r *WsMsg) WriteMessageChan() (data []byte, err error) {
	select {
	case r.outChan <- data:
	case <-r.closeChan:
		err = errors.New("connection is closeed")
	}
	return
}
func (r *WsMsg) Close(conn *websocket.Conn) {
	// 线程安全，可多次调用
	conn.Close()
	// 利用标记，让closeChan只关闭一次
	r.mutex.Lock()
	if !r.isClosed {
		close(r.closeChan)
		r.isClosed = true
	}
	r.mutex.Unlock()
}
func (r *WsMsg) readLoop(conn *websocket.Conn) {
	var (
		data []byte
		err  error
	)
	for {
		_, data, err = conn.ReadMessage()
		if err != nil {
			goto ERR
		}
		fmt.Println("读取的数据:", data)
		//阻塞在这里，等待inChan有空闲位置
		select {
		case r.inChan <- data:
		case <-r.closeChan: // closeChan 感知 conn断开
			goto ERR
		}

	}

ERR:
	r.Close(conn)
}
func (r *WsMsg) writeLoop(conn *websocket.Conn) {
	var (
		data []byte
		err  error
	)

	for {
		select {
		case data = <-r.outChan:
		case <-r.closeChan:
			goto ERR
		}
		//发二进制数据
		if err = conn.WriteMessage(websocket.BinaryMessage, data); err != nil {
			goto ERR
		}
	}

ERR:
	r.Close(conn)

}
func (r *WsMsg) ReadMessage(conn *websocket.Conn) (int, []byte, error) {
	return conn.ReadMessage()
}
func (r *WsMsg) ReadMessageHandle(conn *websocket.Conn, handles ...handle) {
	for _, handle := range handles {
		handle(conn)
	}
}
func (r *WsMsg) WriterMessage(messageType int, data []byte, targetConns ...*websocket.Conn) {
	for _, conn := range targetConns {
		err := conn.WriteMessage(messageType, data)
		if err != nil {
			log.Println("write:", err)
			continue
		}
	}
}
func (r *WsMsg) WriterMessageHandle(conn *websocket.Conn, handles ...handle) {
	for _, handle := range handles {
		handle(conn)
	}
}
func (r *WsMsg) WriterClaims(messageType int, wm iWebsocketClaims, targetConns ...*websocket.Conn) {
	marshal, err := json.Marshal(wm)
	if err != nil {
		return
	}
	r.WriterMessage(messageType, marshal, targetConns...)
}
